import os
import re
from uuid import uuid4
from chardet import detect

from config.ConfigReader import ConfigReader


class TextConverter:
    config_reader = None
    path = os.getcwd()
    DToMDict = {}
    TitleMaxSize = 7
    TitleBold = 1
    EnglishDefaultFont = "Times New Roman"
    # 部分配置文件默认值与参数类型
    ConfigDict = {
        "TitleMaxSize": (int, 7, 5, 7),
        "TitleBold": (int, 1, 0, 1),
        "EnglishDefaultFont": (str, "Times New Roman")
    }
    _ConfigureBackup = {
        'icons': {'icon': r'/assets/img/icon.png', 'about': r'/assets/img/about.png', 'convert': r'/assets/img/convert.png',
                  'exit': r'/assets/img/exit.png', 'help': r'/assets/img/help.png', 'new': r'/assets/img/new.png',
                  'maximize': r'/assets/img/maximize.png', 'minimize': r'/assets/img/minimize.png',
                  'open': r'/assets/img/open.png', 'restore': r'/assets/img/restore.png', 'save': r'/assets/img/save.png'},
        'styles': {'QButton': 'QToolButton,QPushButton{padding-top: 5px; padding-bottom: 5px;}',
                   'QToolBar': 'QToolBar{background-color: #82B7DB; spacing: 15px;}',
                   'textEditBg': 'background-color:#CBDCE9;'},
        'fonts': {'TitleMaxSize': '7', 'TitleBold': '1', 'EnglishDefaultFont': 'Times New Roman'},
        'settings': {'FixedSize': '1'}, 'files': {'RecentFile': '[]'}
    }
    _DefaultConfig = ['styles', 'fonts', 'settings']

    @classmethod
    def _loadConfig(cls, flag = False):
        if cls.config_reader == None or flag:
            cls.config_reader = ConfigReader(cls.path + "\config\config.ini")
            for confName in cls.ConfigDict:
                confValue = cls.config_reader.get_fonts(confName)
                cls._configToType(confValue, confName)
            cls._dToMDict()

    @classmethod
    def _configToType(cls, value, name):
        try:
            typeMethod = cls.ConfigDict[name]
            value = typeMethod[0](value)
            if typeMethod[0] == int:
                value = value if value >= typeMethod[2] and value <= typeMethod[3] else typeMethod[1]
            setattr(TextConverter, name, value)

        except Exception as e:
            pass

    @classmethod
    def _dToMDict(cls):
        for i in range(0, 4):
            cls.DToMDict[str(cls.TitleMaxSize - i)] = "#" * (i + 1)
        cls.DToMDict["Min"] = ""

    @classmethod
    def discuzToMarkdown(cls, text: str) -> str:
        cls._loadConfig()
        def _quote(text):
            text = re.sub(r'\n*(\[quote\].*?\[/quote\])\n*', "\g<1>", text, flags=re.S)
            text = re.sub(r'(\[quote\])(.*?)(\[/quote\])', lambda m: m.group(1) + "\n" + m.group(2).strip() + "\n" + m.group(3), text,
                          flags=re.S)
            text = re.sub(r'(\[/quote\])(\[quote\])', '\g<1>\n\g<2>', text, flags=re.S)
            text = re.sub(r'((?<!\n)\[quote\])|(\[/quote\](?!\n))',
                          lambda m: "\n" + m.group(1) if m.group(1) != None else m.group(2) + "\n", text, flags=re.S)
            text = re.sub(r'\[quote\](.*?)\n\[/quote\]', lambda m: m.group(1).replace("\n", "\n> "),text, flags=re.S)
            return text

        text, dict_code = cls._replace(r"\[code\].*?\[/code\]", text, re.S)
        calcTitle = lambda m: (cls.DToMDict[
            str(cls.TitleMaxSize) if int(m.group(1)) > cls.TitleMaxSize else "Min" if (
                    int(m.group(1)) <= cls.TitleMaxSize - 4) else str(m.group(1))]) + " " + m.group(4)
        tag_list = {
            r'(\[font=.*?\](.*?)\[/font\])': r'\g<2>',
            r'\[size=(\d+)\]((\[b\])?(.*?)(\[/b\])?)\[/size\]': calcTitle,
            r'\[backcolor=.*?\]\[color=.*?\]\[b\](.+?)\[/b\]\[/color\]\[/backcolor\]': r'`\g<1>`',
            r'\[b\](.*?)\[\/b\]': r'**\1**',
            r'\[i\](.*?)\[\/i\]': r'*\1*',
            r'\[u\](.*?)\[\/u\]': r'<u>\1</u>',
            r'\[align=center\](.*?)\[\/align\]': r'<center>\1</center>',
            r'\[hr\]': '---',
            r'\[s\](.*?)\[\/s\]': r'~~\1~~',
            r'\[url=(.*?)\](.*?)\[/url\]': r'[\2](\1)',
            r'\[code\]\n*([\s\S]*?)\n*\[\/code\]': r'```\n\1\n```'
        }

        for pattern, replace in tag_list.items():
            if "font" in pattern:
                text = re.sub(pattern, replace, text)
            elif "code" in pattern:
                text = cls._recovery(dict_code, text)
                text = re.sub(pattern, replace, text)
            else:
                text = re.sub(pattern, replace, text, flags=re.DOTALL)
        text = _quote(text)
        return text.strip()

    @classmethod
    def markdownToDiscuz(cls, text: str) -> str:
        cls._loadConfig()

        def _quote_to_Discuz(text):
            result, temp, new_text = [], [], []
            for i in text.splitlines():
                if i[0:1] != ">":
                    if temp != []:
                        new_text.append("[quote]" + "\n".join(temp) + "[/quote]")
                        temp = []
                    new_text.append(i)
                    result.append(i)
                else:
                    temp.append(i.strip()[2 if i.strip()[1:2] == " " else 1:])
            if temp != []:
                new_text.append("[quote]" + "\n".join(temp) + "[/quote]")
            return "\n".join(new_text)

        b_start, b_end = ("[b]", "[/b]") if cls.TitleBold else ("", "")
        text = re.sub(r'```\n*(.*?)\n*```', r'[code]\n\1\n[/code]', text, flags=re.DOTALL)
        text, dict_code = cls._replace(r"\[code\].*?\[/code\]", text, re.S)
        tag_list = {
            r'\[(.*?)\]\((http[s]?://[^\s\[\]]+)\)': r'[url=\2]\1[/url]',
            r'((\n#+)\s*(.*))|(^(#+)\s*(.*))': lambda
                m: ("" if m.group(1) == None else "\n") + rf"[size={(cls.TitleMaxSize - m.group(0).count('#') + 1) if (cls.TitleMaxSize - m.group(0).count('#') + 1) > 0 else 1}]{b_start + (m.group(3) if m.group(3) != None else m.group(6)) + b_end}[/size]",
            r'\*\*(.*?)\*\*': r'[b]\1[/b]',
            r'\*(.*?)\*': r'[i]\1[/i]',
            r'<u>(.*?)</u>': r'[u]\1[/u]',
            r'<center>(.*?)</center>': r'[align=center]\1[/align]',
            r'---\n': '[hr]\n',
            r'~~(.*?)~~': r'[s]\1[/s]',
            r'```\n*(.*?)\n*```': r'[code]\n\1\n[/code]',
            r"`(.+?)`": r"[backcolor=Gainsboro][color=black][b]\g<1>[/b][/color][/backcolor]"
        }
        for pattern, replace in tag_list.items():
            if "#" in pattern or "http" in pattern:
                text = re.sub(pattern, replace, text)
            else:
                text = re.sub(pattern, replace, text, flags=re.DOTALL)
        # 引用匹配转换
        text = _quote_to_Discuz(text)
        # [url]、普通 url 临时替换
        text, dict_url = cls._replace(
            r"\[url=?https?:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]*[-A-Za-z0-9+&@#\/%=~_|](?=(?:[^`]*`[^`]*`)*[^`]*$)\].*\[/url\]",
            text)
        text, dict_url2 = cls._replace(
            r"https?:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]*[-A-Za-z0-9+&@#\/%=~_|](?=(?:[^`]*`[^`]*`)*[^`]*$)", text)

        # 英文将使用 Times New Roman 字体
        text = re.sub(r"[a-zA-Z]+(?![^\[]*\])", f"[font={cls.EnglishDefaultFont}]\g<0>[/font]", text)

        text = cls._recovery(dict_code, text)
        text = cls._recovery(dict_url, text)
        text = cls._recovery(dict_url2, text)

        return text.strip()

    @staticmethod
    def _replace(pattern, text, flags=0):
        codeDict = {}
        while data := re.search(pattern, text, flags):
            id = str(uuid4())
            text = re.sub(pattern, f"[{id}]", text, count=1, flags=flags)
            codeDict[id] = data.group(0)

        return text, codeDict

    @staticmethod
    def _recovery(codeDict, text):
        for i, j in codeDict.items():
            text = re.sub("\[" + i + "\]", j, text, count=1)
        return text

    @staticmethod
    def _getFileEncoding(file):
        with open(file, "rb") as f:
            result = detect(f.read())
            encoding = result["encoding"]
        if encoding:
            return encoding
        return "utf-8"

    # 暂未实现 -> 文本转换时检测类型
    @classmethod
    def _checkType(cls, text):
        pass
